/*
 * GroupTransactionsFacadeImpl.java    ver   27/nov/2009
 *
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */
package org.mentalsmash.tazio.transactions.management.rm;

import org.mentalsmash.documentation.Concurrency;
import org.mentalsmash.tazio.commons.identifiers.OID;
import org.mentalsmash.tazio.transactions.TransactionStatus;
import org.mentalsmash.tazio.transactions.TransactionalSystemRuntimeException;
import org.mentalsmash.tazio.transactions.management.TazioTransaction;
import org.mentalsmash.tazio.transactions.management.TxStateObserver;
import org.mentalsmash.tazio.transactions.modules.OutcomeObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

/**
 * @version 0.0.1 27/nov/2009
 * @author Andrea Reale <andrea.reale@gmail.com>
 * 
 */
@Concurrency(concurrentAccess = true, specification = "The GroupTransactionsFacadeImpl's only method is called"
	+ "whenever a thread need to commit a transaction. Even tough"
	+ "the RMTransactionManager is already synchronized on is commits,"
	+ "the GroupTransactionFacadeImpl needs to guarantee that the calls"
	+ "to TransactionManager.commit() are executed in the same order of arrival"
	+ "of calls to GroupTransactionsFacadeImpl(). Hence the synchornizaed around"
	+ "the whole doCommit() method")
@Singleton
class GroupTransactionsFacadeImpl implements GroupTransactionsFacade {

    private final static Logger log = LoggerFactory
	    .getLogger(GroupTransactionsFacadeImpl.class);
    private final RMTransactionManager localTxManager;
    private final Provider<TxStateObserver> observerProvider;

    @Inject
    GroupTransactionsFacadeImpl(final RMTransactionManager txManager,
	    @OutcomeObserver Provider<TxStateObserver> stateObserver) {

	this.localTxManager = txManager;
	this.observerProvider = stateObserver;

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.mentalsmash.tazio.transactions.management.rm.GroupTransactionsFacade
     * #doCommit(org.mentalsmash.tazio.transactions.identifiers.OID,
     * org.mentalsmash.tazio.transactions.management.TazioTransaction)
     */
    @Override
    public synchronized void doCommit(final OID srcManager,
	    final TazioTransaction tx) {
	Preconditions.checkNotNull(tx);
	Preconditions.checkNotNull(srcManager);
	Preconditions
		.checkArgument(tx.getStatus() == TransactionStatus.GLOBAL_VALIDATION);

	// localSrc is true if the commit request was received on the local RM
	final boolean localSrc = srcManager.equals(localTxManager
		.getManagerName());

	// Register the tx on the log
	this.localTxManager.getTransactionsLog().logTransaction(tx);
	log.debug("Transactions log got {} registered", tx.getTransactionId());

	// check whether the request was originated locally, in such a case
	// register the Facade
	// as a listener for transactions event
	if (localSrc) {
	    tx.registerStateObserver(this.observerProvider.get());
	    log.debug("RMFacade got {} registered", tx.getTransactionId());
	}

	if (!localTxManager.offerTransactionForCommit(tx)) {
	    log.debug("Transaction {} refused by Transaction Manager", tx
		    .getTransactionId());
	    throw new TransactionalSystemRuntimeException("Transaction refused");
	} else {
	    log.debug("{} was accepted by the RMTM", tx.getTransactionId());
	}

    }

}
